<?
/**
 * This file is part of XNAT light.
 *
 * XNAT light is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * XNAT light is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with XNAT light.  If not, see <http://www.gnu.org/licenses/>.
 */
namespace NRG\Database\Mappers;

use NRG\Xnat as Xnat;
use NRG\Xnat\Scan as Scan;
use NRG\Framework\Exceptions\QueryException as QueryException;
use NRG\Framework\Exceptions\IllegalArgumentException as IllegalArgumentException;

/**
 * MR Session mapper
 *
 * @package NRG\Database\Mappers
 */
class MrSession extends Mapper
{
    /**
     * Accession ID
     *
     * @var string
     */
    protected $_id;

    /**
     * Constructor
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Retrieve MR Session object based on accession
     *
     * @param string $id Accession ID
     * @return NRG\Xnat\MrSession
     * @throws QueryException
     */
    public function byId($id=null)
    {
        if(!is_string($id))
            throw new IllegalArgumentException("ID must be a string");
        else if($id == "")
            throw new IllegalArgumentException("ID cannot be null");

        $sessions = $this->byList(array($id));

        if(sizeof($sessions) == 0)
            return null;
        else if(sizeof($sessions) > 1)
            throw new QueryException(QueryException::MULTI_ROW, "Mapper\MrSession::byId()", array($id));

        return current($sessions);
    }

    /**
     * Retrieve an array of MR Sessions by ID list
     *
     * @param array $list
     * @return array (int, NRG\Xnat\MrSession)
     * @throws NRG\Framework\Exceptions\QueryException
     */
    public function byList(array $list)
    {
        $nItems = count($list);

        if($nItems == 0)
            throw new IllegalArgumentException("List cannot be empty");

        /**
         * Retrieve general information about MR Session
         */
        // build where clause
        $where = "xmsd.id=$1";
        for($i = 2; $i <= $nItems; $i++)
            $where .= " OR xmsd.id=$" . $i;

        // build query
        $query = "SELECT * FROM xnat_mrSessionData AS xmsd, xnat_experimentdata AS xed, " .
            "xnat_subjectassessordata xsad WHERE (xmsd.id=xed.id) AND (xmsd.id=xsad.id) " .
            "AND ($where)";

        $result = $this->_xnat->query($query, $list);

        if(count($result) == 0)
            throw new QueryException(QueryException::EMPTY_RESULT, $query, $list);

        $sessions = array();

        foreach($result as $row)
        {
            $id = $row["id"];

            $sessions[$id] = new Xnat\MrSession();
            $sessions[$id]->setID($id);
            $sessions[$id]->setLabel($row["label"]);
            $sessions[$id]->setCoil($row["coil"]);
            $sessions[$id]->setDate($row["date"]);
            $sessions[$id]->setFieldStrength($row["fieldstrength"]);
            $sessions[$id]->setMarker($row["marker"]);
            $sessions[$id]->setStabilization($row["stabilization"]);
            $sessions[$id]->setPatientName($row["dcm_patientname"]);
            $sessions[$id]->setParentID($row["subject_id"]);
	}

	/**
	 * Retrieve all scan information
	 */
	// build where clause
	$where = "image_session_id=$1";
	for($i = 2; $i <= $nItems; $i++)
	    $where .= " OR image_session_id=$" . $i;

	// retrieve scan information
	$query = "SELECT * FROM xnat_imagescandata WHERE $where";
	$result = $this->_xnat->query($query, $list);

	foreach($result as $row)
	{
	    $scan = new Xnat\Scan($row["image_session_id"]);
	    $scan->setScanNumber();
	    $scan->setScanNumber($row["id"]);
	    $scan->setType($row["type"]);
	    $scan->setQuality($row["quality"]);
	    $scan->setNote($row["note"]);
	    $scan->setSeriesDescription($row["series_description"]);
	    $scan->setManufacturer($row["scanner_manufacturer"]);
	    $scan->setModel($row["scanner_model"]);
	    $scan->setOperator($row["operator"]);
	    $scan->setBay($row["bay"]);

	    $sessions[$row["image_session_id"]]->addScan($scan);
	}

	/**
	 * Retrieve archive status
	 */
	// build where clause
	$where = "id=$1";
	for($i = 2; $i <= $nItems; $i++)
	    $where .= " OR id=$" . $i;

	$query = "SELECT id FROM wrk_workflowdata WHERE status!='Complete' AND ($where)";
	$result = $this->_xnat->query($query, $list);

	foreach($result as $row)
	    $sessions[$row["id"]]->setArchived(false);

	/**
	 * Retrieve all assessors
	 */
	// build where clause
	$where = "xiad.imagesession_id=$1";
	for($i = 2; $i <= $nItems; $i++)
	    $where .= " OR xiad.imagesession_id=$" . $i;

	$query = "SELECT xmad.id AS assessor_id, xiad.imagesession_id AS session_id " .
		"FROM xnat_mrassessordata xmad, xnat_imageassessordata xiad " .
		"WHERE (xmad.id=xiad.id) AND ($where)";
	$result = $this->_xnat->query($query, $list);

	foreach($result as $row)
	    $sessions[$row["session_id"]]->addAssessor($row["assessor_id"]);

	return $sessions;
    }

    /**
     * Get MR Session Accession IDs given a MR Session label
     *
     * @param string $label
     * @param string $project
     * @return array
     */
    public function getAccessionIDs($label=null, $project=null)
    {
	if(!is_string($label))
	    throw new IllegalArgumentException("Label must be a string");
	else if(trim($label) == "")
	    throw new IllegalArgumentException("Label cannot be empty");

	$params = array($label);
	$query = "SELECT id FROM xnat_experimentdata WHERE label=$1";

    if (!empty($project))
    {
        $params[]=$project;
        $query.=" AND project=$2";
    }

	$result = $this->_xnat->query($query, $params);

	$ids = array();

	foreach($result as $row)
	    $ids[] = $row["id"];

	return $ids;
    }

    /**
     * Get MR Session label given Accession ID
     *
     * @param string $id
     * @return string
     * @throws Framework\Exceptions\QueryException
     */
    public function getLabel($id)
    {
	if(!is_string($id))
	    throw new IllegalArgumentException("ID must be a string");
	else if(trim($id) == "")
	    throw new IllegalArgumentException("ID cannot be empty");

	$params = array($id);
	$query = "SELECT label FROM xnat_experimentdata WHERE id=$1";
	$result = $this->_xnat->query($query, $params);

	if(sizeof($result) > 1)
	    throw new QueryException(QueryException::MULTI_ROW, $query, $params);
	else if(sizeof($result) == 0)
	    return null;
	
	$row = current($result);
	return $row["label"];
    }

    /**
     * Get MRSession insert info
     *
     * @param string $id
     * @return string
     */
    public function getInsertInfo($id=null)
    {
	$result=Array();
	$params=Array();

	$query='SELECT s.label, s.project, u.login,m.insert_date,m.status 
		FROM xdat_user u, xnat_experimentdata s, xnat_experimentdata_meta_data m, 
		xnat_mrsessiondata mr 
		WHERE u.xdat_user_id=m.insert_user_xdat_user_id 
		AND mr.mrsessiondata_info=m.meta_data_id 
		AND mr.id=s.id 
		AND s.project IS NOT NULL';

	if (!empty($id))
	{
	    if(!is_string($id))
	        throw new IllegalArgumentException("ID must be a string");
	    else if(trim($id) == "")
	        throw new IllegalArgumentException("ID cannot be empty");

	    $params = array($id);
		
	    $query.=' AND s.id=$1';
	}

        $qresult = $this->_xnat->query($query, $params);

	if(sizeof($qresult) == 0)
	    return null;

	foreach ($qresult as $row)
	    $result[]=$row;


	return $result;
    }



    /**
     * Get MR Session label given a wildcard
     *
     * @param string $wildcard
     * @return array
     */
    public function getWildcardLabels($wildcard)
    {
	if(!is_string($wildcard))
	    throw new IllegalArgumentException("Wildcard must be a string");
	else if(trim($wildcard) == "")
	    throw new IllegalArgumentException("Wildcard cannot be empty");

	$params = array($wildcard);
	$query = "SELECT label FROM xnat_mrsessiondata JOIN xnat_experimentdata
	    ON (xnat_experimentdata.id=xnat_mrsessiondata.id) WHERE label LIKE $1;";
	$result = $this->_xnat->query($query, $params);

	$labels = array();

	foreach($result as $row)
	    $labels[] = $row["label"];

	return $labels;
    }

    /**
     * Get MR Session IDs given a wildcard label
     *
     * @param string $wildcard
     * @return array
     */
    public function getWildcardIDs($wildcard)
    {
	if(!is_string($wildcard))
	    throw new IllegalArgumentException("Wildcard must be a string");

	$params = array($wildcard);
	$query = "SELECT id from xnat_mrsessiondata WHERE id LIKE $1";
	$result = $this->_xnat->query($query, $params);

	$ids = array();

	foreach($result as $row)
	    $ids[] = $row["id"];

	return $ids;
    }

    /**
     * Get ID and label for MR Session that do not have a particular assessment
     *
     * @param string $name
     * @return array
     */
    public function withoutAssessment($name)
    {
        if(!is_string($name))
            throw new IllegalArgumentException("Assessment name must be a string");

        if(empty($name))
            throw new IllegalArgumentException("Assessment name must have a value");

        if(strlen($name) < 3)
            throw new IllegalArgumentException("Assessment name must contain at least 3 characters");

        $name = strtr(strtoupper($name),'*','%');

	$query = 'SELECT xnat_mrsessiondata.id, xnat_experimentdata.label FROM xnat_mrsessiondata '.
		 'JOIN xnat_experimentdata ON (xnat_experimentdata.id=xnat_mrsessiondata.id) '.
		 'WHERE xnat_mrsessiondata.id NOT IN ('.
		 'SELECT imagesession_id FROM xnat_imageassessordata '.
		 'WHERE UPPER(id) LIKE $1);';

        return $this->_xnat->query($query,array($name));
    }

    /**
     * Get ID and label for MR Session that contain an assessment
     *
     * @param string $name
     * @return array
     */
    public function withAssessment($name)
    {
        if(!is_string($name))
            throw new IllegalArgumentException("Assessment name must be a string");


        if(empty($name))
            throw new IllegalArgumentException("Assessment name must have a value");

        if(strlen($name) < 3)
            throw new IllegalArgumentException("Assessment name must contain at least 3 characters");

        $name = strtr(strtoupper($name),'*','%');

	$query = 'SELECT xnat_mrsessiondata.id, xnat_experimentdata.label FROM xnat_mrsessiondata '.
		 'JOIN xnat_experimentdata ON (xnat_experimentdata.id=xnat_mrsessiondata.id) '.
		 'WHERE xnat_mrsessiondata.id IN ('.
		 'SELECT imagesession_id FROM xnat_imageassessordata '.
		 'WHERE UPPER(id) LIKE $1);';

        return $this->_xnat->query($query,array($name));
    }

     /**
     * Get MR Session info by MR Session label and project
     *
     * @param string $label
     * @param string $project
     */
    public function infoByLabel($label, $project)
    {	
	$query = "SELECT xnat_mrsessiondata.id AS aid, xnat_experimentdata.label AS label, 
		  xnat_projectdata.name as plabel, xnat_experimentdata.project as pid 
		  FROM xnat_mrsessiondata 
		  JOIN xnat_experimentdata ON (xnat_mrsessiondata.id=xnat_experimentdata.id) 
		  JOIN xnat_projectdata ON (xnat_experimentdata.project=xnat_projectdata.id)
		  WHERE xnat_experimentdata.label=$1
		  AND (xnat_experimentdata.project=$2 OR xnat_projectdata.name=$2)";

	$result = $this->_xnat->query($query, array($label, $project));

	if(count($result) == 0)
	    return null;

	return $result;
    }

    public function infoById($id=null)
    {
	$query = "select xnat_mrsessiondata.id as aid, xnat_experimentdata.label as label,
	    project as pid, xnat_projectdata.name as plabel from xnat_mrsessiondata
	    JOIN xnat_experimentdata ON (xnat_mrsessiondata.id=xnat_experimentdata.id)
	    JOIN xnat_projectdata ON (xnat_experimentdata.project=xnat_projectdata.id)";

	if($id)
	    $query .= " WHERE xnat_mrsessiondata.id=$1;";

	$result = $this->_xnat->query($query, array($id));

	if(count($result) == 0)
	    return null;

	return $result;
    }

    public function setDateAdded($id,$value)
    {
        if (!is_string($id))
            throw new IllegalArgumentException("MRSession ID must be a string");

        if (!is_string($value))
            throw new IllegalArgumentException("New MRSession insert date must be a string");

        $id=trim($id);
        if (empty($id))
            throw new IllegalArgumentException("MRSession ID cannot be empty");

        $value=trim($value);
        if (empty($value))
            throw new IllegalArgumentException("Date cannot be empty");

        //Check for illegal characters
        if (strlen($value)!==strspn($value,"0123456789:- "))
            throw new IllegalArgumentException("The format of the date parameter is 'YYYY-MM-DD hh:mm:ss'");

        $params=Array($id);
        $query="UPDATE xnat_mrsessiondata_meta_data SET insert_date=timestamp '$value', activation_date=timestamp '$value' WHERE meta_data_id=(SELECT mrsessiondata_info FROM xnat_mrsessiondata WHERE id=$1 LIMIT 1)";

        $result=$this->_xnat->query($query,$params);
    }

    public function setAddedByUser($id,$userid)
    {
        if (!is_string($id))
            throw new IllegalArgumentException("MRSession ID must be a string");

        if (!is_numeric($userid))
            throw new IllegalArgumentException("New user id must be numeric");

        $params=array($id,$userid);
        $query="UPDATE xnat_mrsessiondata_meta_data SET insert_user_xdat_user_id=$2, activation_user_xdat_user_id=$2 WHERE meta_data_id=(SELECT mrsessiondata_info FROM xnat_mrsessiondata WHERE id=$1 LIMIT 1)";

        $result=$this->_xnat->query($query,$params);
    }

}
